import math
import threading
import numpy as np
import time
import os
import json
import pandas as pd
from tools.redis_server import RedisServer
from tools.show import *
from monitor_weight import Monitor


# 设置字体以支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题


class TessEvent:
    def __init__(self, config_data):
        self.y_data_queue = None
        self.x_data_queue = None
        self.config_data = config_data
        self.format_str = str(config_data['format_str'])
        self.window_length = timedelta(minutes=int(config_data['time_interval']))
        self.time_move = timedelta(minutes=int(config_data['time_move']))
        self.dist = float(config_data['dist'])
        self.car_max_speed = float(config_data['car_max_speed'])
        self.car_min_speed = float(config_data['car_min_speed'])
        # 定义小客车平均速度为最大速度的0.75倍
        self.car_mean_speed = 0.7 * self.car_max_speed
        # 定义小客车的期望通行时间
        self.car_pass_time = math.ceil(self.dist / self.car_min_speed * 60)
        # 上下游门架ID
        self.up_gantry_id = None
        self.down_gantry_id = None
        # 上下游门架当前数据
        self.current_up_data = []
        self.current_down_data = []
        # 上下游门架上时刻数据
        self.last_up_data = None
        self.last_down_data = None
        # 上下游门架numpy数组
        self.up_gantry = None
        self.down_gantry = None
        # 上游数据列表
        self.up_list = []
        self.up_data_dict = {}
        # 下游数据列表
        self.down_list = []
        self.down_data_dict = {}
        # 数据索引
        self.current_up_i = 0
        self.current_down_i = 0
        # 时间窗口
        self.start_time = None
        self.end_time = None
        # 车型-平均速度
        self.type_speed_dict = {}
        # 车型-通过率
        self.type_pass_rate_dict = {}
        # 前一帧的小客车平均速度记录
        self.last_car_speed = None
        self.num_plots = 5
        # redis 服务器
        self.redis_server = RedisServer(self.config_data["redis_host"], self.config_data["redis_port"],
                                        self.config_data["redis_pd"], self.config_data["redis_password"])
        self.year = None
        self.month = None
        self.day = None
        self.last_car_vlp = None
        self.current_simulated_time = None
        self.data = {}
        self.thread_flag = True

    def init(self):
        try:
            file_path = self.config_data['file_path']
            file_name = os.path.basename(file_path)
            # 使用逗号分隔字符串
            parts = file_name.split(',')
            # 提取前两个部分
            self.up_gantry_id = parts[0]
            # 使用连字符进一步分割第二个部分
            self.down_gantry_id = parts[1].split('-')[0]
            self.year = int(parts[1].split('-')[1][0:4])
            self.month = int(parts[1].split('-')[1][4:6])
            self.day = int(parts[1].split('-')[1][6:8])
            self.start_time = datetime(self.year, self.month, self.day, 0, 0, 0)
            self.end_time = self.start_time + self.window_length

            # 使用pandas读取CSV文件
            df = pd.read_csv(file_path, sep='\t')
            # 清理列名，去除多余的空格和逗号
            df.columns = [col.strip().replace(',', '') for col in df.columns]
            # 清理每行数据中的多余符号
            for col in df.columns:
                df[col] = df[col].str.strip(', ')
            # # 筛选 gantryid 列值为 up_gantry 的所有行
            up_gantry_df = df[df['gantryid'] == self.up_gantry_id]
            down_gantry_df = df[df['gantryid'] == self.down_gantry_id]
            # 将数据转换为NumPy数组
            self.up_gantry = up_gantry_df.to_numpy()
            self.down_gantry = down_gantry_df.to_numpy()
            # 预先将时间字符串转换为datetime对象
            self.up_gantry = [(g[0], g[1], g[2], datetime.strptime(g[3], self.format_str)) for g in self.up_gantry]
            self.down_gantry = [(g[0], g[1], g[2], datetime.strptime(g[3], self.format_str)) for g in self.down_gantry]
            print("Data loaded successfully")

        except Exception as e:
            print(f"Error occurred: {e} in get_all_data()")

    def publish_data(self):
        # 定义起始时间和结束时间
        start_time = datetime(self.year, self.month, self.day, 0, 0, 0)
        end_time = datetime(self.year, self.month, self.day, 23, 59, 59)
        up_index = 0
        down_index = 0
        # 当前模拟时间初始化为开始时间
        self.current_simulated_time = start_time
        while self.current_simulated_time <= end_time:
            if up_index < len(self.up_gantry):
                while (self.current_simulated_time <= self.up_gantry[up_index][3]) and \
                        (self.up_gantry[up_index][3] < self.current_simulated_time + timedelta(seconds=1)):
                    up_data = {"gantryid": self.up_gantry[up_index][0],
                               "vlp": self.up_gantry[up_index][1],
                               "feevehicletype": self.up_gantry[up_index][2],
                               "transtime": self.up_gantry[up_index][3].strftime(self.format_str)
                               }
                    try:
                        self.redis_server.publish(self.config_data["redis_channel"], json.dumps(up_data))
                    except Exception as e:
                        print(e)
                    up_index += 1
            if down_index < len(self.down_gantry):
                while (self.current_simulated_time <= self.down_gantry[down_index][3]) and \
                        (self.down_gantry[down_index][3] < self.current_simulated_time + timedelta(seconds=1)):
                    down_data = {"gantryid": self.down_gantry[down_index][0],
                                 "vlp": self.down_gantry[down_index][1],
                                 "feevehicletype": self.down_gantry[down_index][2],
                                 "transtime": self.down_gantry[down_index][3].strftime(self.format_str)
                                 }
                    try:
                        self.redis_server.publish(self.config_data["redis_channel"], json.dumps(down_data))
                    except Exception as e:
                        print(e)
                    down_index += 1

            # 模拟1秒的流逝
            self.current_simulated_time += timedelta(seconds=1)
            # 等待真实世界中的0.01秒
            time.sleep(0.01)
            if not self.thread_flag:
                break

        print("遍历完成")

    def subscribe_data(self):
        channel = self.config_data["redis_channel"]
        self.redis_server.subscribe(channel)
        while True:
            messages = self.redis_server.get_messages()
            if messages:
                if self.last_car_vlp is None:
                    self.last_car_vlp = messages[-1]['vlp']
                elif messages[-1]['vlp'] == self.last_car_vlp:
                    continue
                else:
                    i = -1
                    while messages[i]['vlp'] != self.last_car_vlp and i > -len(messages):
                        if messages[i]['gantryid'] == self.up_gantry_id:
                            self.current_up_data.append(messages[i])
                        else:
                            self.current_down_data.append(messages[i])
                        i -= 1
                    self.last_car_vlp = messages[-1]['vlp']
            time.sleep(0.01)
            if not self.thread_flag:
                break

    def speed_and_pass(self):
        self.type_speed_dict.clear()
        self.type_pass_rate_dict.clear()
        vlp_list = self.down_data_dict.keys()
        for vlp in vlp_list:
            down_time = self.down_data_dict[vlp]['transtime']
            vehicle_type = self.down_data_dict[vlp]['vehicletype']
            # 查找上游门架对应车牌出现时间，计算平均速度
            if vlp in self.up_data_dict.keys():
                up_time = self.up_data_dict[vlp]['transtime']
                dt = down_time - up_time
                dt_hours = dt.total_seconds() / 3600
                speed = self.dist / dt_hours
                speed = round(speed, 2)
                slow_level = 0
                if (speed * 1.5) < self.car_mean_speed:
                    slow_level = 1
                elif (speed * 2.0) < self.car_max_speed:
                    slow_level = 2
                elif (speed * 3.0) < self.car_max_speed:
                    slow_level = 3
                # print(f"VLP:{vlp}, Speed:{speed}")
                # del self.up_data_dict[vlp]
                if vehicle_type not in self.type_speed_dict.keys():
                    self.type_speed_dict[vehicle_type] = {}
                    self.type_speed_dict[vehicle_type]["speed_list"] = []
                    self.type_speed_dict[vehicle_type]["slow_level_list"] = []
                self.type_speed_dict[vehicle_type]["speed_list"].append(speed)
                self.type_speed_dict[vehicle_type]["slow_level_list"].append(slow_level)

                if vehicle_type not in self.type_pass_rate_dict.keys():
                    self.type_pass_rate_dict[vehicle_type] = {}
                    self.type_pass_rate_dict[vehicle_type]["value"] = []
                    self.type_pass_rate_dict[vehicle_type]["vaild_count"] = 0
                    self.type_pass_rate_dict[vehicle_type]["count"] = 0
                self.type_pass_rate_dict[vehicle_type]["value"].append(int(dt_hours * 60))
                self.type_pass_rate_dict[vehicle_type]["count"] += 1

        # 计算平均速度
        for vehicle_type in self.type_speed_dict.keys():
            speed_list = self.type_speed_dict[vehicle_type]["speed_list"].copy()
            slow_level_list = self.type_speed_dict[vehicle_type]["slow_level_list"]
            mean_speed = sum(speed_list) / len(speed_list)
            self.type_speed_dict[vehicle_type]["mean_speed"] = round(mean_speed, 2)
            self.type_speed_dict[vehicle_type]["count"] = len(speed_list)
            # 统计慢行小客车的数量
            level_0 = slow_level_list.count(0)
            level_1 = slow_level_list.count(1)
            level_2 = slow_level_list.count(2)
            level_3 = slow_level_list.count(3)
            # self.type_speed_dict[vehicle_type]["slow_level_count"] = [level_0, level_1, level_2, level_3]
            self.type_speed_dict[vehicle_type]["slow_level_count"] = level_1 + level_2 + level_3

        # 计算通过率
        for vehicle_type in self.type_pass_rate_dict.keys():
            for i in range(len(self.type_pass_rate_dict[vehicle_type]["value"])):
                if self.type_pass_rate_dict[vehicle_type]["value"][i] <= self.car_pass_time:
                    self.type_pass_rate_dict[vehicle_type]["vaild_count"] += 1

    def time_compare(self):
        # 当前时刻上游门架数据
        if self.current_up_data:
            if self.current_up_data != self.last_up_data:
                for i in range(len(self.current_up_data)):
                    current_up_time = datetime.strptime(self.current_up_data[i]["transtime"], self.format_str)
                    up_vlp = self.current_up_data[i]["vlp"]
                    self.up_data_dict[up_vlp] = {'vehicletype': self.current_up_data[i]["feevehicletype"],
                                                 'transtime': current_up_time}
                    self.up_list.append(current_up_time)
                self.last_up_data = self.current_up_data
                self.current_up_data = []

        # 当前时刻下游门架数据
        if self.current_down_data:
            if self.current_down_data != self.last_down_data:
                for i in range(len(self.current_down_data)):
                    current_down_time = datetime.strptime(self.current_down_data[i]["transtime"], self.format_str)
                    down_vlp = self.current_down_data[i]["vlp"]
                    self.down_data_dict[down_vlp] = {'vehicletype': self.current_down_data[i]["feevehicletype"],
                                                     'transtime': current_down_time}
                    self.down_list.append(current_down_time)
                self.last_down_data = self.current_down_data
                self.current_down_data = []

        if self.current_simulated_time is not None and self.current_simulated_time > self.end_time:
            # 移动时间窗口
            self.start_time += self.time_move
            self.end_time += self.time_move
            # print(f"Move to next time window: {self.start_time}, {self.end_time}")

            # 计算时间窗口内的车流量
            up_flow_num = len(self.up_list)
            down_flow_num = len(self.down_list)

            # 计算下游门架各车型车辆平均速度
            self.speed_and_pass()
            type_speed_dict = self.type_speed_dict.copy()
            type_pass_rate_dict = self.type_pass_rate_dict.copy()

            # 清除过早数据
            i = j = 0
            while i < len(self.up_list):
                if self.up_list[i] < self.start_time:
                    i += 1
                else:
                    break
            self.up_list = self.up_list[i:]
            while j < len(self.down_list):
                if self.down_list[j] < self.start_time:
                    j += 1
                else:
                    break
            self.down_list = self.down_list[j:]

            # 清除过期数据(一小时前未匹配上的上游门架数据)
            del_up_vlp_list = []
            up_vlp_list = self.up_data_dict.keys()
            for vlp in up_vlp_list:
                data_time = self.up_data_dict[vlp]['transtime']
                if data_time < self.start_time - timedelta(minutes=60):
                    del_up_vlp_list.append(vlp)
                else:
                    break
            for vlp in del_up_vlp_list:
                del self.up_data_dict[vlp]
            del_down_vlp_list = []
            down_vlp_list = self.down_data_dict.keys()
            for vlp in down_vlp_list:
                data_time = self.down_data_dict[vlp]['transtime']
                if data_time < self.start_time:
                    del_down_vlp_list.append(vlp)
                else:
                    break
            for vlp in del_down_vlp_list:
                del self.down_data_dict[vlp]

            # 清空数据
            # self.down_data_dict.clear()
            # self.type_speed_dict.clear()
            return [up_flow_num, down_flow_num, type_speed_dict, type_pass_rate_dict]

        return None

    def run(self):
        # 初始化
        self.init()
        # 实时发布门架数据
        publish = threading.Thread(target=self.publish_data)
        publish.daemon = True
        publish.start()
        # 实时监听最新门架数据
        subscribe = threading.Thread(target=self.subscribe_data)
        subscribe.daemon = True
        subscribe.start()

        monitor = Monitor(self.config_data)
        Content = []

        while True:
            Info = self.time_compare()
            if Info is not None:
                Info_time = self.end_time - self.time_move
                count = 0
                for vehicle_type in Info[2].keys():
                    count += Info[2][vehicle_type]["count"]
                self.data[Info_time] = {
                    "up_flow_num": Info[0],
                    "down_flow_num": Info[1],
                    "type_speed_dict": Info[2],
                    "type_pass_rate_dict": Info[3],
                    "total_match": count
                }
                data = {
                    "time": Info_time - self.time_move,
                    "total_match": count,
                    "up_flow_num": Info[0],
                    "down_flow_num": Info[1],
                    "type_speed_dict": Info[2],
                    "type_pass_rate_dict": Info[3]

                }
                last_data_time = Info_time - self.window_length
                if last_data_time in self.data.keys():
                    last_data = {
                        "time": last_data_time,
                        "total_match": self.data[last_data_time]["total_match"],
                        "up_flow_num": self.data[last_data_time]["up_flow_num"],
                        "down_flow_num": self.data[last_data_time]["down_flow_num"],
                        "type_speed_dict": self.data[last_data_time]["type_speed_dict"],
                        "type_pass_rate_dict": self.data[last_data_time]["type_pass_rate_dict"]
                    }
                    content = monitor.run(data, last_data)
                    if content is not None:
                        print(content)
                        Content.append(content)



                # {Info_time: {"up_flow_num": int,
                #              "down_flow_num": int,
                #              "type_speed_dict": {vehicle_type: {"speed_list": [],
                #                                                 "slow_level_list": [],
                #                                                 "mean_speed": int,
                #                                                 "count": int,
                #                                                 "slow_level_count": int}},
                #              "type_pass_rate_dict": {vehicle_type: {"value": [],
                #                                                     "vaild_count": int,
                #                                                     "count": int}
                #                                      },
                #              "total_match": int
                #              }
                #  }

                print(Info_time, Info[0], Info[1])
                end_time = datetime(self.year, self.month, self.day, 23, 50, 00)

                if Info_time >= end_time:
                    with open("./output/event3.txt", 'w', encoding="utf-8") as f:
                        for i in range(len(Content)):
                            f.write(Content[i] + "\n")
                        f.close()
                    save_pass_path = './output/pass_rate.png'
                    show_pass_rate(self.data, SHOW=False, SAVE=True, SAVE_PATH=save_pass_path)
                    save_speed_path = './output/mean_speed.png'
                    show_speed(self.data, TYPE="1", SHOW=False, SAVE=True, SAVE_PATH=save_speed_path)
                    save_slow_path = './output/slow_num.png'
                    show_slow_num(self.data, TYPE="1", SHOW=False, SAVE=True, SAVE_PATH=save_slow_path)
                    save_flow_path = './output/flow.png'
                    show_flow(self.data, SHOW=False, SAVE=True, SAVE_PATH=save_flow_path)
                    save_match_path = './output/match.png'
                    show_match(self.data, SHOW=False, SAVE=True, SAVE_PATH=save_match_path)
                    save_duration_path = './output/time_duration.png'
                    show_time_duration(self.data, TYPE=None, SHOW=False, SAVE=True, SAVE_PATH=save_duration_path)

                    self.thread_flag = False
                    break
            time.sleep(0.01)


if __name__ == "__main__":
    config_data = None
    config_file = "./config.json"
    with open(config_file, 'r', encoding='utf-8') as f:
        try:
            config_data = json.load(f)
            print(config_data)
        except Exception as e:
            print("Error: Could not load config file", e)
        tessEvent = TessEvent(config_data)
        tessEvent.run()

